package cube.data;

import static cube.data.util.DataUtil.min;

import java.util.ArrayList;
import java.util.List;

import cube.data.util.DataUtil;
import cube.data.util.ListUtil;
import cube.utils.StringUtil;

/**
 * 字节数组缓冲区
 * 
 * @author abiao
 */
public class ByteBuffer {

    /**
     * 字节缓冲区
     */
    private List<Byte> buffer = new ArrayList<Byte>();

    /**
     * 二进制缓冲区
     */
    private FiFo<Integer> binBuffer = new FiFo<Integer>();

    /**
     * 十六进制缓冲区
     */
    private FiFo<Character> hexBuffer = new FiFo<Character>();

    /**
     * 指针位置
     */
    private int p;

    /**
     * 字节数组缓冲区
     */
    public ByteBuffer() {
    }

    /**
     * 字节数组缓冲区初始化
     */
    public ByteBuffer(byte[] data) {
        this.buffer = ListUtil.bytes2list(data);
    }

    /**
     * 获取缓冲区数据
     */
    public byte[] getData() {
        return ListUtil.list2bytes(buffer);
    }

    /**
     * 读出size个字符
     */
    public String readString(int size) {
        return new String(read(size));
    }

    /**
     * 读一个整形值
     */
    public int readInt() {
        return DataUtil.bytes2int(read(DataUtil.INT_LEN));
    }

    /**
     * 读size个字节为整形
     */
    public int readInt(int size) {
        return DataUtil.bytes2int(read(size));
    }

    /**
     * 读一个短整形
     */
    public short readShort() {
        return DataUtil.bytes2short(read(DataUtil.SHORT_LEN));
    }

    /**
     * 读size个字节为短整形
     */
    public short readShort(int size) {
        return DataUtil.bytes2short(read(size));
    }

    /**
     * 读一个长整形
     */
    public long readLong() {
        return DataUtil.bytes2long(read(DataUtil.LONG_LEN));
    }

    /**
     * 读size个字节为长整形
     */
    public long readLong(int size) {
        return DataUtil.bytes2long(read(size));
    }

    /**
     * 读一个字节
     */
    public byte read() {
        cleanBuffers();
        return buffer.get(p++);
    }

    /**
     * 读size个字节
     */
    public byte[] read(int size) {
        int readable = 0;
        if (hasNext()) {
            readable = min(size, buffer.size() - p);
        }
        byte[] data = new byte[readable];
        for (int i = 0; i < data.length; i++) {
            data[i] = read();
        }
        return data;
    }

    /**
     * 读取剩余所有字节
     */
    public byte[] readAll() {
        return read(buffer.size() - p);
    }

    /**
     * 读一个比特位
     */
    public int readBit() {
        if (binBuffer.empty()) {
            String bin = DataUtil.hex2bin(readHex());
            for (int i = 0; i < bin.length(); i++) {
                binBuffer.put(DataUtil.bin2int(bin.charAt(i) + ""));
            }
        }
        return binBuffer.top();
    }

    /**
     * 读一个十六进制值
     */
    public char readHex() {
        cleanBinBuffer();
        if (hexBuffer.empty()) {
            byte b = read();
            hexBuffer.put(DataUtil.getHighHex(b));
            hexBuffer.put(DataUtil.getLowHex(b));
        }
        return hexBuffer.top();
    }

    /**
     * 读n个bcd编码的字符串
     */
    public String readBCD(int n) {
        StringBuffer dec = new StringBuffer();
        for (int i = 0; i < n; i++) {
            dec.append(readHex());
        }
        return dec.toString();
    }

    /**
     * 读n个bcd编码的字符串，去除占位字符
     */
    public String readBCD(int n, char occupy) {
        return StringUtil.removeAll(readBCD(n), occupy);
    }

    /**
     * 读出int格式的bcd编码数值
     */
    public int readBCDInt(int n) {
        return Integer.parseInt(readBCD(n));
    }

    /**
     * 读取到达结尾
     */
    public boolean hasNext() {
        return p < buffer.size();
    }

    /**
     * 跳过size个字节不读
     */
    public void skip(int size) {
        if (size > 0) {
            p += size;
        }
    }

    /**
     * 写入字节数组
     */
    public void write(byte[] data) {
        for (int i = 0; i < data.length; i++) {
            write(data[i]);
        }
    }

    /**
     * 写入一个字节
     */
    public void write(byte data) {
        cleanBuffers();
        buffer.add(data);
    }

    /**
     * 写入一个短整形
     */
    public void write(short data) {
        write(DataUtil.short2bytes(data));
    }

    /**
     * 写入short值的低size个字节
     */
    public void write(short data, int size) {
        write(DataUtil.copytail(DataUtil.short2bytes(data), size));
    }

    /**
     * 写入一个整形
     */
    public void write(int data) {
        write(DataUtil.int2bytes(data));
    }

    /**
     * 写入int值的低size个字节
     */
    public void write(int data, int size) {
        write(DataUtil.copytail(DataUtil.int2bytes(data), size));
    }

    /**
     * 写入一个长整形
     */
    public void write(long data) {
        write(DataUtil.long2bytes(data));
    }

    /**
     * 写入long值的低size个字节
     */
    public void write(long data, int size) {
        write(DataUtil.copytail(DataUtil.long2bytes(data), size));
    }

    /**
     * 写入字符串
     */
    public void write(String s) {
        write(s.getBytes());
    }

    /**
     * 写入bcd编码字符串
     */
    public void writeBCD(String dec) {
        for (int i = 0; i < dec.length(); i++) {
            writeHex(dec.charAt(i));
        }
    }

    /**
     * 写入bcd编码字符串，不够bcdSize时前面自动补'0'
     * 
     * @param dec bcd十进制字符串
     * @param bcdSize bcd编码的长度
     */
    public void writeBCD(String dec, int bcdSize) {
        writeBCD(StringUtil.addOccupy('0', dec, bcdSize));
    }

    /**
     * 写入bcd编码字符串
     * 
     * @param dec 十进制字符串
     * @param bcdSize bcd编码的长度
     * @param occupy 尾部占位符（十六进制字符），比如'f', 'F'等
     */
    public void writeBCD(String dec, int bcdSize, char occupy) {
        writeBCD(StringUtil.addOccupy(dec, bcdSize, occupy));
    }

    /**
     * 写入一个二进制位
     */
    public void writeBit(int bit) {
        binBuffer.put(bit);
        if (binBuffer.size() % 4 == 0) {
            flushBinToHexBuffer();
        }
    }

    /**
     * 写入n个二进制位
     */
    public void writeBit(int bit, int n) {
        for (int i = 0; i < n; i++) {
            writeBit(bit);
        }
    }

    /**
     * 写入一个十六进制
     */
    public void writeHex(char hex) {
        hexBuffer.put(hex);
        if (hexBuffer.size() == 2) {
            flushHexToByteBuffer();
        }
    }

    /**
     * 写入n个十六进制
     */
    public void writeHex(char hex, int n) {
        for (int i = 0; i < n; i++) {
            writeHex(hex);
        }
    }

    /**
     * 清空二进制和十六进制缓冲区
     */
    private void cleanBuffers() {
        cleanBinBuffer();
        cleanHexBuffer();
    }

    /**
     * 清空二进制缓冲区
     */
    private void cleanBinBuffer() {
        if (!binBuffer.empty()) {
            binBuffer.clear();
        }
    }

    /**
     * 清空十六进制缓冲区
     */
    private void cleanHexBuffer() {
        if (!hexBuffer.empty()) {
            hexBuffer.clear();
        }
    }

    /**
     * 将十六进制缓冲区的数值刷新到字节缓冲区
     */
    private void flushHexToByteBuffer() {
        String hex = getBufferString(hexBuffer);
        write(DataUtil.hex2byte(hex));
    }

    /**
     * 将二进制缓冲区的数值刷新到十六进制缓冲区
     */
    private void flushBinToHexBuffer() {
        String bin = getBufferString(binBuffer);
        byte b = DataUtil.bin2byte(bin);
        writeHex(DataUtil.getLowHex(b));
    }

    /**
     * 获取缓冲区中的字符串
     */
    private String getBufferString(FiFo<?> buffer) {
        StringBuffer sb = new StringBuffer();
        while (!buffer.empty()) {
            sb.append(buffer.top());
        }
        return sb.toString();
    }

    /**
     * 清空字节缓存
     */
    public void clear() {
        buffer.clear();
        binBuffer.clear();
        hexBuffer.clear();
        p = 0;
    }

    /**
     * 当前字节缓冲区字节数
     */
    public int size() {
        return buffer.size();
    }
}
